//
//  matrix.c
//  linear_algebra
//
//  Created by zhangnan on 2025/3/24.
//

#include "matrix.h"
#include <stdio.h>
#include <stdlib.h>
#include "../utils/common.h"

/**
 创建一个double类型矩阵
 */
MATRIX_DOUBLE_TYPE new_double_matrix(double *arr, int param_rows, int param_cols)
{
    MATRIX_DOUBLE_TYPE result;
    result.rows = param_rows;
    result.cols = param_cols;
    result.array = arr;
    return result;
}

/**
 根据行列获取矩阵值（double）
 */
double get_value_from_double_matrix(MATRIX_DOUBLE_TYPE *matrix, int row_index, int col_index)
{
    return matrix->array[matrix->cols * row_index + col_index];
}

/**
 创建一个int类型的矩阵
 */
MATRIX_INT_TYPE new_int_matrix(double *arr, int param_rows, int param_cols)
{
    MATRIX_INT_TYPE result;
    result.rows = param_rows;
    result.cols = param_cols;
    result.array = arr;
    return result;
}

/**
 根据行列获取矩阵值（int）
 */
int get_value_from_int_matrix(MATRIX_INT_TYPE *matrix, int row_index, int col_index)
{
    return matrix->array[matrix->cols * row_index + col_index];
}

// 动态创建 MATRIX_DOUBLE_TYPE 结构体
MATRIX_DOUBLE_TYPE *create_double_matrix(int rows, int cols)
{
    // 为结构体分配内存
    MATRIX_DOUBLE_TYPE *matrix = (MATRIX_DOUBLE_TYPE *)malloc(sizeof(MATRIX_DOUBLE_TYPE));
    if (matrix == NULL)
    {
        fprintf(stderr, "无法为结构体分配内存\n");
        return NULL;
    }

    // 为二维数组分配内存
    matrix->array = (double *)malloc(rows * cols * sizeof(double));
    if (matrix->array == NULL)
    {
        fprintf(stderr, "无法为二维数组分配内存\n");
        free(matrix);
        return NULL;
    }

    // 初始化结构体成员
    matrix->rows = rows;
    matrix->cols = cols;

    return matrix;
}

// 释放 MATRIX_DOUBLE_TYPE 结构体占用的内存
void free_double_matrix(MATRIX_DOUBLE_TYPE *matrix)
{
    if (matrix != NULL)
    {
        // 释放二维数组的内存
        if (matrix->array != NULL)
        {
            free(matrix->array);
        }
        // 释放结构体本身的内存
        free(matrix);
    }
}

// 动态创建 MATRIX_INT_TYPE 结构体
MATRIX_INT_TYPE *create_int_matrix(int rows, int cols)
{
    // 为结构体分配内存
    MATRIX_INT_TYPE *matrix = (MATRIX_INT_TYPE *)malloc(sizeof(MATRIX_INT_TYPE));
    if (matrix == NULL)
    {
        fprintf(stderr, "无法为结构体分配内存\n");
        return NULL;
    }

    // 为二维数组分配内存
    matrix->array = (int *)malloc(rows * cols * sizeof(int));
    if (matrix->array == NULL)
    {
        fprintf(stderr, "无法为二维数组分配内存\n");
        free(matrix);
        return NULL;
    }

    // 初始化结构体成员
    matrix->rows = rows;
    matrix->cols = cols;

    return matrix;
}

// 释放 MATRIX_INT_TYPE 结构体占用的内存
void free_int_matrix(MATRIX_INT_TYPE *matrix)
{
    if (matrix != NULL)
    {
        // 释放二维数组的内存
        if (matrix->array != NULL)
        {
            free(matrix->array);
        }
        // 释放结构体本身的内存
        free(matrix);
    }
}

/**
 * 创建一个分数矩阵
 *
 * @param arr 一个指向分数数组的指针，用于初始化矩阵
 * @param param_rows 矩阵的行数
 * @param param_cols 矩阵的列数
 * @return 返回一个指向新创建的分数矩阵的指针，若失败则返回 NULL
 *
 * 此函数通过接受一个分数数组和矩阵的行列参数，创建并初始化一个分数矩阵。
 * 它负责分配必要的内存，并通过复制给定数组中的值来填充矩阵。
 * 如果内存分配失败或参数非法，则返回 NULL。
 */
MATRIX_FRACTION_TYPE *create_fraction_matrix(FRACTION_TYPE **arr, int param_rows, int param_cols)
{
    // 参数校验
    if (arr == NULL || param_rows <= 0 || param_cols <= 0)
    {
        return NULL; // 非法参数
    }

    // 分配内存
    MATRIX_FRACTION_TYPE *matrix = (MATRIX_FRACTION_TYPE *)malloc(sizeof(MATRIX_FRACTION_TYPE));
    if (matrix == NULL)
    {
        return NULL; // 内存分配失败
    }

    // 初始化矩阵
    matrix->rows = param_rows;
    matrix->cols = param_cols;
    matrix->array = (FRACTION_TYPE *)malloc(param_rows * param_cols * sizeof(FRACTION_TYPE *));
    if (matrix->array == NULL)
    {
        free(matrix); // 释放已分配的内存
        return NULL;  // 内存分配失败
    }

    for (int i = 0; i < param_rows; i++)
    {
        // 复制数据
        for (int j = 0; j < param_cols; j++)
        {
            matrix->array[i * param_cols + j] = arr[i * param_cols + j];
        }
    }

    return matrix;
}

/**
 创建一个全为0的矩阵
 */
MATRIX_FRACTION_TYPE *create_simple_fraction_matrix(int param_rows,int param_cols){
    // 参数校验
    if ( param_rows <= 0 || param_cols <= 0)
    {
        return NULL; // 非法参数
    }

    // 分配内存
    MATRIX_FRACTION_TYPE *matrix = (MATRIX_FRACTION_TYPE *)malloc(sizeof(MATRIX_FRACTION_TYPE));
    if (matrix == NULL)
    {
        return NULL; // 内存分配失败
    }

    // 初始化矩阵
    matrix->rows = param_rows;
    matrix->cols = param_cols;
    matrix->array = (FRACTION_TYPE *)malloc(param_rows * param_cols * sizeof(FRACTION_TYPE *));
    if (matrix->array == NULL)
    {
        free(matrix); // 释放已分配的内存
        return NULL;  // 内存分配失败
    }

    for (int i = 0; i < param_rows; i++)
    {
        // 复制数据
        for (int j = 0; j < param_cols; j++)
        {
            matrix->array[i * param_cols + j] = new_simple_fraction(0);
        }
    }

    return matrix;
}

/**
 * 从分数矩阵中获取特定位置的值
 *
 * @param matrix 一个指向分数矩阵的指针
 * @param row_index 目标值在矩阵中的行索引
 * @param col_index 目标值在矩阵中的列索引
 * @return 返回指向该位置的分数的指针，若索引非法或矩阵为空则返回 NULL
 *
 * 此函数根据给定的行和列索引，从分数矩阵中检索特定位置的分数值。
 * 如果索引越界或矩阵为空，则返回 NULL。
 */
FRACTION_TYPE *get_value_from_fraction_matrix(MATRIX_FRACTION_TYPE *matrix, int row_index, int col_index)
{
    // 参数校验
    if (matrix == NULL || row_index < 0 || col_index < 0 || row_index >= matrix->rows || col_index >= matrix->cols)
    {
        return NULL; // 索引非法或矩阵为空
    }

    return &(matrix->array[row_index * matrix->cols + col_index]);
}

/**
 * 释放分数矩阵占用的内存
 *
 * @param matrix 一个指向分数矩阵的指针
 *
 * 此函数负责释放与分数矩阵相关的所有内存资源。
 * 如果传入的矩阵指针为 NULL，则直接返回。
 */
void free_fraction_matrix(MATRIX_FRACTION_TYPE *matrix)
{
    if (matrix == NULL)
    {
        return; // 空指针直接返回
    }

    // 释放矩阵数据
    for (int i = 0; i < matrix->rows; i++)
    {
        for (int j = 0; j < matrix->cols; j++)
        {
            free_fraction(&matrix->array[i * matrix->cols + j]);
        }
    }
    free(matrix->array); // 释放行指针数组
    free(matrix);        // 释放矩阵结构体本身
}

/**
 * 打印分数矩阵
 *
 * 该函数接受一个指向分数矩阵的指针作为参数，并将其内容打印到控制台如果传入的指针为NULL，
 * 则会打印出"NULL"并退出函数此函数首先打印矩阵的基本信息，如行数和列数，
 * 然后逐行打印矩阵中的每个分数元素
 *
 * @param matrix 指向分数矩阵的指针如果为NULL，函数将打印"NULL"并返回
 */
void print_fraction_matrix(MATRIX_FRACTION_TYPE *matrix)
{
    // 检查矩阵指针是否为NULL
    if (matrix == NULL)
    {
        printf("NULL\n");
        return;
    }

    // 打印分数矩阵的基本信息
    printf("fraction matrix:\n");
    printf("rows: %d, cols: %d\n", matrix->rows, matrix->cols);

    // 遍历并打印矩阵中的每个元素
    for (int i = 0; i < matrix->rows; i++)
    {
        for (int j = 0; j < matrix->cols; j++)
        {
            if (matrix->array[i * matrix->cols + j]->denominator == 1)
            {
                printf("%d\t", matrix->array[i * matrix->cols + j]->numerator);
            }
            else
            {
                // 以分数形式打印每个元素
                printf("%d/%d\t", matrix->array[i * matrix->cols + j]->numerator, matrix->array[i * matrix->cols + j]->denominator);
            }
        }
        // 换行，准备打印下一行
        printf("\n");
    }
}

/**
 转换为阶梯型
 */
void trans_to_echelon(MATRIX_FRACTION_TYPE *matrix)
{
    if (matrix == NULL || matrix->rows <= 0 || matrix->cols <= 0) {
        // 检查矩阵是否为空或无效
        return;
    }
    //转换
    matrix=trans_zero_to_echelon(matrix);
    print_fraction_matrix(matrix);
    // 第一次迭代
    int index=0;
    
    while(index<matrix->rows&&index<matrix->cols){
        int first_index=index;
        for(int i=index;i<matrix->rows;i++){
            int fz=0;
            int fm=1;
            int flag=0;
            if(index==i){
                for(int j=index;j<matrix->cols;j++){
                    if(get_fraction_matrix_value(matrix, i, j)->numerator==0){
                        continue;
                    }else{
                        if(flag==0){
                            fz=get_fraction_matrix_value(matrix, i, j)->denominator;
                            fm=get_fraction_matrix_value(matrix, i, j)->numerator;
                            
                            flag=1;
                            first_index=j;
                            set_fraction_matrix_value(matrix, multi_fractions(get_fraction_matrix_value(matrix, i, j), new_fraction(fz, fm)), i, j);
                        }else{
                            set_fraction_matrix_value(matrix, multi_fractions(get_fraction_matrix_value(matrix, i, j), new_fraction(fz, fm)), i, j);
                        }
                    }
                }
                print_fraction_matrix(matrix);
            }else{
                int fz=0;
                int fm=1;
                int flag=0;
                for(int j=first_index;j<matrix->cols;j++){
                    
                    if(get_fraction_matrix_value(matrix, i, j)->numerator==0){
                        break;
                    }else{
                        if(flag==0){
                            fz=get_fraction_matrix_value(matrix, i, j)->numerator;
                            fm=get_fraction_matrix_value(matrix, i, j)->denominator;
                            flag=1;
                        }
                        
//                        if((fz>0&&fm<0)||(fz<0&&fm>0)){
//                            fz=-fz;
//                        }
                        
                        set_fraction_matrix_value(matrix,sub_fractions(get_fraction_matrix_value(matrix, i, j), multi_fractions(get_fraction_matrix_value(matrix, index, j), new_fraction(fz, fm))), i, j);
                    }
                }
                print_fraction_matrix(matrix);
            }
            
        }
        index++;
    }
    // 打印
    print_fraction_matrix(matrix);

}

/**
 交换两列让行列式0较多的列放在后面
 */
MATRIX_FRACTION_TYPE * trans_zero_to_echelon(MATRIX_FRACTION_TYPE *matrix){
    int *arr = (int *)malloc(matrix->rows * sizeof(int));
    if(arr==NULL){
        printf("内存分配失败\n");
        return NULL;
    }
    for(int i=0;i<matrix->rows;i++){
        int count=0;
        for(int j=0;j<matrix->cols;j++){
            if(get_fraction_matrix_value(matrix, i, j)->numerator==0){
                count++;
            }else{
                break;
            }
        }
        arr[i]=count;
    }
    ValueIndex *vi = (ValueIndex *)malloc(matrix->rows * sizeof(ValueIndex));
    if (vi == NULL) {
        printf("内存分配失败\n");
        return NULL;
    }

    // 初始化结构体数组，存储值和对应的索引
    for (int i = 0; i < matrix->rows; i++) {
        vi[i].value = arr[i];
        vi[i].index = i;
    }

    // 使用 qsort 对结构体数组按值排序
    qsort(vi, matrix->rows, sizeof(ValueIndex), compare);
    
    
    
    MATRIX_FRACTION_TYPE *result=create_simple_fraction_matrix(matrix->rows, matrix->cols);
    
    // 输出排序后的索引
    for (int i = 0; i < matrix->rows; i++) {
        
        for(int j=0;j<matrix->cols;j++){
            set_fraction_matrix_value(result, get_fraction_matrix_value(matrix, vi[i].index, j), i, j);
        }
    }
    free(arr);
    free(vi);
    
    return result;
}


/**
 * 设置分数矩阵中的特定元素值
 * 
 * @param matrix 指向要设置值的分数矩阵
 * @param fraction 指向要设置值的分数矩阵
 * @param row_index 行索引，表示矩阵中的行位置
 * @param col_index 列索引，表示矩阵中的列位置
 * 
 * 此函数用于将分数矩阵中指定位置的元素设置为新的分数值通过行索引和列索引定位到具体位置
 */
void set_fraction_matrix_value(MATRIX_FRACTION_TYPE *matrix,FRACTION_TYPE *fraction,int row_index,int col_index){
    matrix->array[matrix->cols*row_index+col_index]=fraction;
}

/**
 * 获取分数矩阵中特定元素的值
 * 
 * @param matrix 指向分数矩阵的指针，从该矩阵中获取元素值
 * @param row_index 行索引，指定所需元素所在的行
 * @param col_index 列索引，指定所需元素所在的列
 * @return 返回指定位置的分数值如果位置无效，返回值是未定义的
 * 
 * 此函数用于从分数矩阵中获取指定位置的元素值通过行索引和列索引来定位元素位置
 */
FRACTION_TYPE * get_fraction_matrix_value(MATRIX_FRACTION_TYPE *matrix,int row_index,int col_index){
    return matrix->array[matrix->cols * row_index + col_index];
}
